/*
 * Copyright 2010 Michael Nitsche
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package de.mnit.basis.daten.struktur.tabelle;

import java.util.Iterator;

import de.mnit.basis.daten.struktur.S_Folge;
import de.mnit.basis.daten.struktur.liste.Liste;
import de.mnit.basis.daten.struktur.liste.S_Liste;
import de.mnit.basis.daten.struktur.ordnen.Sortieren;
import de.mnit.basis.fehler.Fehler;
import de.mnit.basis.sys.Ausgabe;


/**
 * @author Michael Nitsche
 */
public abstract class A_Tabelle<T> implements S_Tabelle<T> {

	// LESEN

	public S_Liste<T> gZeile(int z) {
		S_Liste<T> zeile=Liste.neu();
		for(int i=0; i<gBreite(); i++)
			zeile.plus(this.gib(i+1, z));
		return zeile;
	}

	public S_Liste<T> gSpalte(int spalte) {
		Fehler.zahl.wenn_Ausserhalb(gBreite(),spalte);
		Fehler.zahl.wenn_Gleich(spalte, 0);

		if(spalte<0)
			spalte=gBreite()+spalte+1;
		return pGibSpalte(spalte);
	}

	public T gib(int spalte, int zeile) {
		return this.gSpalte(spalte).gib(zeile);
	}

	public S_Folge<T> gib(int zeile) {
		return this.gZeile(zeile);
	}

	public Iterator<S_Folge<T>> iterator() {
		final S_Tabelle<T> tabelle=this;
		return new Iterator<S_Folge<T>>(){

			private int naechstezeile=1;

			public boolean hasNext() {
				return naechstezeile<=tabelle.gLaenge();
			}

			public S_Folge<T> next() {
				return tabelle.gZeile(naechstezeile++);
			}

			public void remove()   { Fehler.sonstige.da_Untypisch("Funktion ungültig!"); }

		};
	}

	public int gLaenge() {
		return this.pGibSpalte(1).gLaenge();
	}

	public boolean istLeer() {
		return gLaenge()==0;
	}

	public void ausgeben() {
		Ausgabe.debugVersetzt(1, zuTextDebug());
	}

	public String toString() {
		StringBuffer sb=new StringBuffer();
		for(int zeile=1; zeile<=gLaenge(); zeile++) {
			for(int spalte=1; spalte<=gBreite(); spalte++)
				sb.append(gib(spalte,zeile) + (spalte!=gBreite() ? "," : ""));
			sb.append("\n");
		}
		return sb.toString();
	}

	// AENDERN

	public void setze(int spalte, int zeile, T objekt) {
		Fehler.zahl.wenn_Ausserhalb(1,gLaenge(),zeile);
		Fehler.zahl.wenn_Ausserhalb(1,gBreite(),spalte);
		pSetze(spalte, zeile, objekt);
	}

	public void ersetzen(int zeile, T... objekte) {
		Fehler.zahl.wenn_Ausserhalb(gLaenge(), zeile);
		Fehler.zahl.wenn_InListe(zeile,0);
		for(int i=1; i<=gBreite(); i++)
			pSetze(i, zeile, objekte[i-1]);
	}

	public void vertauschen(int zeile_a, int zeile_b) {
		Fehler.zahl.wenn_InListe(zeile_a,0);
		Fehler.zahl.wenn_InListe(zeile_b,0);

		Fehler.zahl.wenn_Ausserhalb(1,gLaenge(), Math.abs(zeile_a));
		Fehler.zahl.wenn_Ausserhalb(1,gLaenge(), Math.abs(zeile_b));

		if( zeile_a == zeile_b ) {
			Ausgabe.warnung("Vertauschen von "+(zeile_a)+" und "+(zeile_b)+" nicht nötig!");
			return;
		}

		pVertauschen(zeile_a, zeile_b);
	}

	public S_Liste<T> minus(int pos) {
		S_Folge<T> zeile=this.gZeile(pos);
		pMinus(pos);
		S_Liste<T> erg=Liste.neu();
		for(T o : zeile)
			erg.plus(o);
		return erg;
	}

	public void sortieren(int... nach)   { Sortieren.sortieren(this, nach); }

	// GESCHUETZT

	protected abstract S_Liste<T> pGibSpalte(int spalte);
	protected abstract void pSetze(int spalte, int zeile, T objekt);
	protected abstract void pMinus(int pos);
	protected abstract void pVertauschen(int zeile_a, int zeile_b);

}
